package main

import (
	"fmt"
)

/*
1、go语音中函数支持普通函数，匿名函数(匿名函数是一种没有指定函数名的函数声明方式)，闭包
2、go中函数是"一等公民"
	1、函数本身可以当做变量
	2、支持匿名函数、闭包、普通函数
	3、函数可以满足接口
3、定义函数的关键字为func
*/

/*
	一、普通函数定义
	func 函数名(参数1 参数1类型, 参数2 参数2类型) (返回值1类型, 返回值2类型){
    }
	如上是一个有入参和返回值的函数的定义，当然有些情况下可以简写，并且参数在传递的时候再go语言中都是值传递
	函数可以有参和无参，返回值可以有单值，多值，也可以没有返回值，返回值也可以直接定义量
	函数的返回值也可以是函数  func 函数名1() func(){} 在这后面的func()表示该函数的返回值为函数，返回值函数还可以带参数
*/

// 1、定义固定个数参数的有参函数
func add1(a int, b int) int {
	a = 4
	return a + b
}

// 这里可以看到当参数类型一样的时候可以把一样的参数简写到一起，返回的值可以是多个，也可以没返回值
func del(a, b int, c float32) (int, error) {
	result := 0
	result = a - b
	return result, nil

}

// 也可以在定义函数的时候，直接把返回值变量定义好，函数中直接引用
func add2(a int, b int) (sum int, err error) {
	a = 4
	sum = a + b
	err = nil
	return sum, err
}

// 2、定义参数个数为动态不固定的函数 格式：func add3(参数名 ...类型){}，用...省略号来表示参数个数不固定，个数可以0，也可以是多个
func add3(itmes ...int) (sum int) {
	// 用一个变量items来接收传入进行的不固定个数的参数，items的类型为slice，变量的名称随便
	// 用for循环遍历入参
	fmt.Printf("itmes %T\n", itmes)
	for key, value := range itmes {
		fmt.Printf("%d  %d\n", key, itmes[key])
		sum += value
	}
	fmt.Println()
	return sum

}

// 3、定义部分参数固定，部分参数为动态参数

func add4(des string, itmes ...int) {
	//如上可以看到第一个参数des参数，必须传递进来，后面的为动态参数个数不固定，可以传，也可以不传
	fmt.Println(des)
	fmt.Println(itmes)
}

func main() {
	a := 1
	b := 2
	// 调用函数
	fmt.Println(add1(a, b))
	fmt.Println(a) // 在函数add中修改了a的值，但是并没有改变main中定义的a的值，因为函数参数是值传递，复制的副本到函数中的
	delValue, _ := del(a, b, 3.1)
	fmt.Println(delValue)
	//调用不固定参数个数的函数
	fmt.Println(add3(1, 2, 3, 4))
	//调用定义部分参数固定，部分参数为动态参数
	add4("小姜")
}
